/**
 * Created by Xiang on 2017/7/14
 * 题目基础模型
 */
const VariableTypes = {numeric: '数值型', nominal: '标称型'};
const variableToke = function (name) {
  return '#' + name + '#';
};
const answerToken = function (name) {
  return '@' + name + '@';
};
/**
 * 从sub随机到sup
 */
const randomRange = function (sub, sup) {
  return sub + Math.random() * (sup - sub);
};
/**
 * 变量工厂
 * @param type 类型,{'numeric': '数值型', 'nominal': '标称型'}
 * @param range 范围 [1,3]
 * @param fixed 固定小数位数
 * @param ratio 扩大倍数
 * @param perturbation 自定义扰动函数 (a)=>return a
 * @returns {{type: *, range: *, next: (function())}}
 */
const Variables = function ({type, range, fixed, ratio, perturbation}) {
  let next;
  if (type === 'numeric') {
    next = function () {
      let num = 0;
      if (range instanceof Array && range[0] !== null && range[1] !== 0) {
        num = randomRange(range[0], range[1]);
      }
      if (fixed !== undefined && fixed !== null) {
        num = num.toFixed(fixed);
      }
      if (ratio !== undefined && ratio !== null) {
        num *= ratio;
      }
      if (perturbation !== null && perturbation instanceof Function) {
        num = perturbation(num);
      }
      return num;
    }
  } else {
    next = function () {
      let index = Math.floor(randomRange(0, range.length));
      return range[index];
    }
  }
  return {
    type,
    range,
    next
  }
};
/**
 * 模板替换
 */
const applyVariable = function (template, name, value) {
  return template.replace(variableToke(name), value);
};
/**
 * 题目属性
 * @param content 内容
 * @param options 选项
 * @param answerContent 答案内容
 * @param answer 答案
 * @param analyse 分析
 * @param hints 提示
 * @param next 随机题目
 * @returns {{content: *, answerContent: *, answer: *, analyse: *, hints: *, next: *}}
 * @constructor
 */
const Question = function ({content, options, answerContent, answer, analyse, hints, next, type}) {
  return {
    content,
    options,
    answerContent,
    answer,
    analyse,
    hints,
    next,
    type
  }
};
const ModelType = {
  BaseModel: '基础模型',
  BaseChoiceModel: '基础选择题模型',
  Unknown: '未知模型'
};
/**
 * 模型基类,基础填空题
 * @param template 模板，一空
 * @param variables 变量列表 {name:'',value:0,...Variable}
 * @param answerTemplate 答案模板,填空题必须要包含至少一个input
 * @param answerFunc 答案 是一个function
 * @param analyseTemplate 分析模板
 * @param hintTemplates 提示模板数组，有顺序的数组
 * @constructor
 */
const BaseModel = function ({template, variables, answerTemplate, answerFunc, analyseTemplate, hintTemplates, note}) {
  let next = function () {
    let content = template, answerContent = answerTemplate, analyse = analyseTemplate, hints = hintTemplates;
    //随机下一道题时
    //先随机每一个变量
    //用变量值替换掉所有模板
    for (let variable of variables) {
      variable.value = variable.next();
      content = applyVariable(content, variable.name, variable.value);
      answerContent = applyVariable(answerContent, variable.name, variable.value);
      analyse = applyVariable(analyse, variable.name, variable.value);
      let hintTemps = [];
      for (let hint of hints) {
        hint = applyVariable(hint, variable.name, variable.value);
        hintTemps.push(hint);
      }
      hints = hintTemps;
    }
    //计算答案
    let answer = answerFunc(variables);
    return Question({
      content,
      answerContent,
      answer,
      analyse,
      hints,
      note,
      options: null,
      type: ModelType.BaseModel
    });
  };
  return {
    template, variables, answerTemplate, answerFunc, analyseTemplate, hintTemplates, next, note,
    type: ModelType.BaseModel
  }
};
/**
 * 模型基类,基础选择题
 * @param template 模板，一空
 * @param optionTemplates 选项模板
 * @param variables 变量列表 {name:'',value:0,...Variable}
 * @param answerIndex 答案 是选项数组的Index
 * @param analyseTemplate 分析模板
 * @param hintTemplates 提示模板数组，有顺序的数组
 * @constructor
 */
const BaseChoiceModel = function ({template, optionTemplates, variables, answerIndex, analyseTemplate, hintTemplates}) {
  let next = function () {
    let content = template, optionContents = optionTemplates, analyse = analyseTemplate, hints = hintTemplates;
    //随机下一道题时
    //先随机每一个变量
    //用变量值替换掉所有模板
    for (let variable of variables) {
      variable.value = variable.next();
      content = applyVariable(content, variable.name, variable.value);
      optionContents = applyVariable(optionContents, variable.name, variable.value);
      analyse = applyVariable(analyse, variable.name, variable.value);
      let hintTemps = [];
      for (let hint of hints) {
        hint = applyVariable(hint, variable.name, variable.value);
        hintTemps.push(hint);
      }
      hints = hintTemps;
    }
    //计算答案
    let answer = answerFunc(variables);
    return Question({
      content,
      answerContent,
      answer,
      analyse,
      hints,
      type: ModelType.BaseChoiceModel
    });
  };
  return {
    template, variables, answerTemplate, answerFunc, analyseTemplate, hintTemplates, next,
    type: ModelType.BaseChoiceModel
  }
};

export {
  VariableTypes,
  variableToke,
  answerToken,
  Variables,
  BaseModel,
  BaseChoiceModel,
  ModelType
};
